<?php
###########################################################################
#  Copyright (C) 2006-2007 Glyphix, Inc. <briz@glyphix.com>               #
#                                                                         #
#  Permission is hereby granted, free of charge, to any person obtaining  #
#  a copy of this software and associated documentation files (the        #
#  "Software"), to deal in the Software without restriction, including    #
#  without limitation the rights to use, copy, modify, merge, publish,    #
#  distribute, sublicense, and/or sell copies of the Software, and to     #
#  permit persons to whom the Software is furnished to do so, subject to  #
#  the following conditions:                                              #
#                                                                         #
#  The above copyright notice and this permission notice shall be         #
#  included in all copies or substantial portions of the Software.        #
#                                                                         #
#  Except as contained in this notice, the name(s) of the above           #
#  copyright holders shall not be used in advertising or otherwise to     #
#  promote the sale, use or other dealings in this Software without       #
#  prior written authorization.                                           #
#                                                                         #
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        #
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     #
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. #
#  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      #
#  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  #
#  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  #
#  OTHER DEALINGS IN THE SOFTWARE.                                        #
###########################################################################

/**
 * GXGoogleOAuth2
 *
 * Authenticates against a Google account.
 * @author		Brad Brizendine <briz@glyphix.com>
 * @link		http://www.glyphix.com/
 * @license		http://opensource.org/licenses/bsd-license.php BSD License
 * @version		1.0
 * @package		GXPage
 * @subpackage	Modules
 * @copyright	Copyright 2006 - 2007, Glyphix, Inc.
 * @uses		GXModule, curl
 */


// Docs for server-side login with oauth2
// https://developers.google.com/accounts/docs/OpenIDConnect

// Docs for google-api-php-client
// https://github.com/google/google-api-php-client

session_start();
require_once realpath(dirname(__FILE__) .'/Library/google-api-php-client-master/autoload.php');
require_once realpath(dirname(__FILE__) .'/Library/php-jwt-master/Authentication/JWT.php');


class GXGoogleOAuth2 extends GXModule {

	private $GXCookie = null;
	private $GClient = null;

	// populates once the user successfully logs in, see this::freshen
	private $user = null;
	// the token returned by successful login, see this::freshen
	private $token = null;
	private $idtoken = null;
	// the code returned by successful oauth2 login
	private $code = null;
	// session name for $_SESSION
	private $session_name = 'access_token';
	// cookie to track google auth token
	private $authCookieName = 'gtoken';
	// timeout for the cookie
	private $timeout = 15;
	// this member's id ... not the user's email address, because we don't want to have to retrieve that
	private $uid;

	// oauth2 fields
	private $client_id = null;
	private $client_secret = null;
	private $redirect_uri = null;
	private $hd = null;
	private $post_login_uri = null;
	private $authorized = null;

	// init GXModule and process conf
	public function __construct( $config = null ){
		parent::__construct();
		$this->GXCookie = GXCookie::getInstance();
		$this->GClient = new Google_Client();

		// either domain or username+password may be present
		$this->client_id		= $this->getval($config, 'client_id');
		$this->client_secret	= $this->getval($config, 'client_secret');
		$this->redirect_uri		= $this->getval($config, 'redirect_uri');
		$this->hd 				= $this->getval($config, 'hd');
		$this->post_login_uri	= $this->getval($config, 'post_login_uri');
		$this->authorized		= $config->exec->xpath('authorized', 0);

		// prime GClient
		$redirurl = array(
			'http' .(isset($_SERVER['HTTPS']) ? 's' : '') .'://',
			$_SERVER['HTTP_HOST'],
			$this->GXPage->Layout->Client->Root,
			$this->redirect_uri
			);
		$this->GClient->setClientId($this->client_id);
		$this->GClient->setClientSecret($this->client_secret);
		$this->GClient->setRedirectUri(implode('', $redirurl));
		$this->GClient->setHostedDomain($this->hd);
		$this->GClient->setScopes('email');

		// see if we already have a token
		if( $this->isLoggedIn() ){
			$this->freshen();
			trigger_error('>>>>> We have a token:' .$this->token, E_USER_WARNING);
		}else{
			trigger_error( 'User is not authenticated', E_USER_WARNING );
			$this->logout();
		}

		return true;
	}

	public function isLoggedIn(){
		trigger_error('>>> GXGoogleOAuth2::isLoggedIn = ' .isset($_SESSION[$this->session_name]), E_USER_WARNING);
		return (isset($_SESSION[$this->session_name]) && $_SESSION[$this->session_name]);
	}

	/*
	 * showUser
	 * Builds XML for the current user.
	 * @return object GXDOM
	 */
	public function showUser(){
		$user = new GXDOM('User');
		$user->FirstName( $this->uid );
		$user->LastName();
		$auth = $user->Auth();
		$auth->Role(null,array('ID'=>'MEMBER'));
		$auth->Role(null,array('ID'=>'ADMIN'));
		return $user;
	}

	public function freshen(){
		$this->token = $_SESSION[$this->session_name];
		$this->GClient->setAccessToken($this->token);
		trigger_error('User *is* authenticated with a google token:' .$_SESSION[$this->session_name], E_USER_WARNING);

		// unpack the token
		$t = $_SESSION[$this->session_name];
		$tobj = json_decode($t);

		// decode the token
		$decoded = JWT::decode($tobj->id_token, $this->client_secret, false);

		// store our user info
		$this->user = (object)array(
			'id' => $decoded->id,
			'email' => $decoded->email,
			'domain' => $decoded->hd
			);

		// all verified and checked out
		return true;
	}

	/**
	 * logout
	 *
	 * Logout function. Duh.
	 * @return boolean
	 */
	public function logout(){
		unset($_SESSION[$this->session_name]);
		$this->GXCookie->delete( $this->authCookieName );

		trigger_error('You have successfully signed out.', E_USER_WARNING);

		return true;
	}

	public function authenticate(){
		$url = $this->GClient->createAuthUrl();
		header('Location: ' .$url);
		exit();
	}

	public function userIsValid($code = null){
		if( ! $code){
			trigger_error('Missing $code:' .$code, E_USER_WARNING);
			return false;
		}

		// store the session
		$this->code = $code;
		$this->GClient->authenticate($code);

		// get the token, then freshen so we know we have the user's email address
		$_SESSION[$this->session_name] = $this->GClient->getAccessToken();
		$this->freshen();

		// if we have this::authorized, verify that the email matches
		$allowed = false;
		if($this->authorized){

			// check against the emails in our config
			$addresses = $this->authorized->exec->xpath('//email');
			foreach($addresses as $e){
				if($this->user->email == $e->nodeValue){
					$allowed = true;
					break;
				}
			}

			// if we didn't find an email we like, kill the session and go home
			if( ! $allowed){
				// if we made it this far, this email address isn't authorized, so kill the session
				$this->logout();

				// go home
				trigger_error('LOGIN ERROR: this email address is not authorized.', E_USER_NOTICE);
				header('Location: ' .$this->GXPage->Layout->Client->BaseHREF);
				exit();
			}
		}

		return true;
	}

	public function getUser(){
		return $this->user;
	}

}
